#include "stdafx.h"
#include "Notify.h"


EventObject::~EventObject() {
	Notify::Remove(this);
}



namespace Notify {
	typedef std::pair<void*, MsgType> KeyType;
	struct Cmp{
		bool operator()(const KeyType& left, const KeyType& right){
			return (left.first == right.first) ? (left.second < right.second) : (left.first < right.first);
		}
	};
	typedef boost::signals2::signal< void (void* instance, MsgType, boost::any) > NotifySignal;
	typedef map< KeyType, boost::shared_ptr<NotifySignal>, Cmp > NotifySignalStore;

	//flag,  0=get, 1=autoCreate, 2=autoDelete
	NotifySignalStore* GetAllSigs(int flag = 0) {
		static NotifySignalStore* allSig = 0;
		switch(flag) {
		case 1: {
			if(!allSig) {
				allSig = new NotifySignalStore();
			}
		}
		break;
		case 2: {
			if(allSig && allSig->empty()) {
				delete allSig;
				allSig = 0;
			}
		}
		break;
		}
		return allSig;
	}

	void Fire(void* instance, MsgType msg, boost::any data) {
		NotifySignalStore* all = GetAllSigs(0);
		if(all) {
			NotifySignalStore::iterator it = all->find(make_pair(instance, msg));
			if(it != all->end()) {
				boost::shared_ptr<NotifySignal> sig = it->second;
				(*sig)(instance, msg, data);
			}
		}
	}
	Connection Add(void* instance, MsgType msg, NotifyCallback callback, int group, Position pos) {
		NotifySignalStore* all = GetAllSigs(1);
		assert(all);
		boost::shared_ptr<NotifySignal> sig;
		NotifySignalStore::iterator it = all->find(make_pair(instance, msg));
		if(it == all->end()) {
			sig.reset(new NotifySignal());
			(*all)[make_pair(instance, msg)] = sig;
		} else {
			sig = it->second;
		}
		if(group) {
			return sig->connect(group, callback, boost::signals2::connect_position(pos) );
		}
		return sig->connect(callback, boost::signals2::connect_position(pos) );
	}
	void Remove(Connection con) {
		con.disconnect();
	}
	void Remove(void* instance, MsgType msg) {
		NotifySignalStore* all = GetAllSigs(0);
		if(all) {
			all->erase(make_pair(instance, msg));
			GetAllSigs(2);
		}
	}
	void Remove(void* instance) {
		NotifySignalStore* all = GetAllSigs(0);
		if(all) {
			NotifySignalStore::iterator  low = all->lower_bound(make_pair(instance, minMsg));
			NotifySignalStore::iterator  up = all->upper_bound(make_pair(instance, maxMsg));
			all->erase(low, up);
			GetAllSigs(2);
		}
	}
};